概述

在程序设计领域,把在无需改写源代码即可让开发出来的程序能够支持多种语言和数据格式的技术称为国际化。

与国际化对应的是本地化,指让一个具备国际化支持的应用程序支持某个特定的地区。

Struts2国际化是建立在Java国际化基础上的:

  • 为不同国家/地区提供对应的消息资源文件
  • Struts2框架会根据请求中包含的Locale加载对应的资源文件
  • 通过程序代码取得资源文件中指定key对应的消息

国际化目标

  • 配置国际化资源文件
    • Action范围资源文件:在Action类文件所在的路径建立名为ActionName_language_country.properties的文件
    • 包范围资源文件:在包的根路径下建立文件名为package_language_country.properties的属性文件,一旦建立,处于该包下的所有Action都可以访问该资源文件,注意:包范围资源文件的baseName就是package,不是Action所在的包名
    • 全局资源文件
      • 命名方式:basename_language_country.properties
      • struts.xml:<constant name="struts.custom.i18n.resources" value="basename"/>
    • 国际化资源文件加载的顺序:离当前Action较近的将被优先加载
    • 一个项目中通常只要一个国际化资源文件,因此推荐使用全局资源文件
  • 在页面上和Action类中访问国际化资源文件的value值
    • 在Action类中,若Action类实现了TextProvider接口,则可以调用其getText()方法获取value值
      • 通过继承ActionSupport的方式
    • 页面上可以使用s:text标签,对于表单标签,可以使用表单标签的key属性值
      • 若有占位符,则可以使用s:text标签的s:param子标签来填充占位符
      • 可以利用标签和OGNL表达式直接访问值栈中的属性值,包括对象栈和Map栈
  • 实现通过超链接切换语言

国际化举例

JSP中国际化的使用

  • 使用xhtml主题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <%@ page language="java" contentType="text/html; charset=GB18030"
    pageEncoding="GB18030"%>
    <%@taglib uri="/struts-tags" prefix="s"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=GB18030">
    <title>Insert title here</title>
    </head>
    <body>
    <s:debug></s:debug>
    <s:form action="" >
    <!--
    若label标签使用%{getText('username')}的方式就也可以从国际化资源文件中获取value值
    因为此时在对象栈中有defaultTextProvider的一个实例,该对象中提供了访问国际化资源文件的 getText()方法
    同时还需要通知Struts2框架label中放入的不再是一个普通的字符串,而是一个OGNL表达式
    -->
    <s:textfield name="username" label="%{getText('username')}"></s:textfield>
    <!-- key的方式是直接上国际化资源文件中获取value值 -->
    <s:textfield name="username" key="username"></s:textfield>
    <s:password name="password" key="password"></s:password>
    <s:submit key="submit"></s:submit>
    </s:form>
    </body>
    </html>

    当然,对于全局资源文件,需要在struts.xml文件中进行配置,如下:

    1
    2
    <!-- 配置国际化资源文件 -->
    <constant name="struts.custom.i18n.resources" value="i18n"></constant>
  • 使用simple主题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <%@ page language="java" contentType="text/html; charset=GB18030"
    pageEncoding="GB18030"%>
    <%@taglib uri="/struts-tags" prefix="s"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=GB18030">
    <title>Insert title here</title>
    </head>
    <body>
    <s:debug></s:debug>
    <s:form action="" theme="simple">
    <!--
    若label标签使用%{getText('username')}的方式就也可以从国际化资源文件中获取value值
    因为此时在对象栈中有defaultTextProvider的一个实例,该对象中提供了访问国际化资源文件的getText()方法
    同时还需要通知Struts2框架label中放入的不再是一个普通的字符串,而是一个OGNL表达式
    -->
    <!--页面上可以直接使用<s:text name="" />来访问国际化资源文件里的value值-->
    <s:text name="username"/>:<s:textfield name="username" label="%{getText('username')}"></s:textfield>
    <!-- key的方式是直接上国际化资源文件中获取value值 -->
    <s:text name="username"/>:<s:textfield name="username" key="username"></s:textfield>
    <s:text name="password"/>:<s:password name="password" key="password"></s:password>
    <s:submit key="submit" value="%{getText('submit')}"></s:submit>
    </s:form>
    </body>
    </html>

    唯一的区别就是当使用simple主题时,表单标签的key属性不起作用,此时需要使用<s:text> 标签,其name属性为国际化资源文件中key的名字。

Action中国际化的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.glemontree.struts;
import java.util.Arrays;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
// 继承自ActionSupport就间接实现了TextProvider接口,可以调用getText()方法
public class TestI18NAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private Date date = null;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public String execute() throws Exception {
date = new Date();
// 在Action中访问国际化资源文件的value值
String username = getText("username");
System.out.println(username);
// 带占位符
String time = getText("time", Arrays.asList(date));
System.out.println(time);
return super.execute();
}
}

通过上面的代码知道,在Action中访问国际化资源的方式是使用getText()方法,当然,前提是Action需要继承自ActionSupport,因为ActionSupport实现了TextProvider接口。

上面的程序中也示范了怎么在Action中访问国际化资源文件中带占位符的资源,那么如何在JSP文件中访问国际化资源文件中带占位符的资源呢?

1
2
3
<s:text name="time">
<s:param value="date"></s:param>
</s:text>

正如上面所述,需要在<s:text>中通过子标签<s:param> 指定占位符的取值,当然这里的date是值栈中的值。

利用超链接实现动态加载国际化资源文件

  • Struts2使用i18n拦截器处理国际化,并且将其注册在默认的拦截器栈中
  • i18n拦截器在执行Action方法前,自动查找请求中一个名为request_locale的参数,如果该参数存在,拦截器就将其作为参数,转换成Locale对象,并将其设为用户默认的Locale,并将其设置为session的WW_TRANS_I18N_LOCALE属性
  • 若request没有名为request_locale的参数,则i18n拦截器会从Session中获取WW_TRANS_I18N_LOCALE的属性值,若该值不为空,则将该属性值设置为浏览器的默认Locale
  • 若session中的WW_TRANS_I18N_LOCALE的属性值为空,则从ActionContext中获取Locale对象

具体实现如下:

1
2
<a href="testI18N.action?request_locale=en_US">English</a>
<a href="testI18N.action?request_locale=zh_CN">中文</a>

注意:超链接必须是一个Struts的请求,即使我们的i18n拦截器工作!错误代码如下:

1
2
<a href="i18n.jsp?request_locale=en_US">English</a>
<a href="i18n.jsp?request_locale=zh_CN">中文</a>

此时请求不会进入Action,自然也不会经过i18n拦截器,i18n拦截器不会工作。